package NIO;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;

import static NIO.ByteBufferUtil.debugAll;

public class NonBlockingServer_Selector {
    private static void split(ByteBuffer source) {
        source.flip();
        for (int i = 0; i < source.limit(); i++) {
            // 找到一条完整消息
            if (source.get(i) == '\n') {
                int length = i + 1 - source.position();
                // 把这条完整消息存入新的 ByteBuffer
                ByteBuffer target = ByteBuffer.allocate(length);
                // 从 source 读，向 target 写
                for (int j = 0; j < length; j++) {
                    target.put(source.get());
                }
                debugAll(target);
            }
        }
        source.compact(); // 0123456789abcdef  position 16 limit 16
    }

    public static void main(String[] args) throws IOException {
        //create the selector to manage channels
        Selector selector=Selector.open();

        ServerSocketChannel ssc=ServerSocketChannel.open();
        ssc.configureBlocking(false);
        ssc.bind(new InetSocketAddress(8080));

        //将ssc注册到selector
        //这里的第二个参数，代表只关注accept事件
        ssc.register(selector, SelectionKey.OP_ACCEPT,null);

        /*
        也可以这么写
        SelectionKey register = ssc.register(selector, 0, null);
        register.interestOps(SelectionKey.OP_ACCEPT);*/

        while (true){
            //没有事件发生的时候阻塞，有事件的时候，线程恢复运行
            //select在有事件未处理的时候，不会阻塞，所以发生了事件后，要么取消，要么处理，不可以置之不理
            selector.select();
            //包含了所有发生的事件
            Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
            while (iterator.hasNext()){
                SelectionKey key = iterator.next();
                //要先删除，否则会出问题（处理前后删除都可以，但一定要删除）
                iterator.remove();
                //根据不同的事件类型，进行处理
                if (key.isAcceptable()){
                    ServerSocketChannel channel =(ServerSocketChannel) key.channel();
                    SocketChannel accept = channel.accept();
                    accept.configureBlocking(false);
                    ByteBuffer byteBuffer=ByteBuffer.allocate(16);
                    //第三个参数，代表附件，是和每一个channel绑定的,可以让每一个channel有属于自己的bytebuffer
                    SelectionKey register = accept.register(selector, 0, byteBuffer);
                    register.interestOps(SelectionKey.OP_READ);
                }else if (key.isReadable()){
                    try{
                        SocketChannel channel=(SocketChannel) key.channel();
                        ByteBuffer byteBuffer=(ByteBuffer) key.attachment();
                        int read = channel.read(byteBuffer);
                        if (read==-1){
                            //没有要读的，需要及时取消相应的key
                            key.cancel();
                        }else {
                            split(byteBuffer);
                            //此时证明需要扩容
                            if (byteBuffer.position()==byteBuffer.limit()){
                                ByteBuffer newByteBuffer=ByteBuffer.allocate(byteBuffer.capacity()*2);
                                byteBuffer.flip();
                                newByteBuffer.put(byteBuffer);
                                key.attach(newByteBuffer);
                            }
                        }
                    }catch (IOException e){
                        e.printStackTrace();
                        //如果客户端在没主动close的情况下被关闭了，会出现异常，来到这个，应该及时把key取消（从selector的keys集中删除key）
                        key.cancel();
                    }

                }


            }
        }
    }
}
